package com.lemon.mybatisplus.base;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lemon.mybatisplus.enums.StatusEnum;
import com.lemon.core.web.Result;
import com.lemon.mybatisplus.properties.MybatisPlusConfigProperties;
import lombok.extern.log4j.Log4j2;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 李猛
 * @datetime 2023/4/15 17:18
 * @description 类对象
 */
@Log4j2
public class BaseServiceImpl<M extends BaseMapper<P>, P, D> extends ServiceImpl<M, P> implements BaseService<P, D> {
    @Override
    public Result<String> add(P p) {
        return this.save(p) ? Result.ok("添加成功！") : Result.fail("添加失败！");
    }

    @Override
    @Transactional
    public Result<String> adds(List<P> ps) {
        return this.saveBatch(ps) ? Result.ok("添加成功！") : Result.fail("添加失败！");
    }

    @Override
    public Result<String> delById(Long id) {
        return this.removeById(id) ? Result.ok("删除成功！") : Result.fail("删除失败！");
    }

    @Override
    @Transactional
    public Result<String> delByIds(Collection<Long> ids) {
        return this.removeBatchByIds(ids) ? Result.ok("删除成功！") : Result.fail("删除失败！");
    }

    @Override
    public Result<String> update(P p) {
        return this.updateById(p) ? Result.ok("修改成功！") : Result.fail("修改失败！");
    }

    @Override
    @Transactional
    public Result<String> updates(List<P> ps) {
        return this.updateBatchById(ps) ? Result.ok("修改成功！") : Result.fail("修改失败！");
    }

    @Override
    @Transactional
    public Result<String> addOrUpdate(P p) {
        boolean result = this.saveOrUpdate(p);
        String type = "修改";
        try {
            Method idMethod = p.getClass().getMethod("getId", new Class[]{});
            Object idObj = idMethod.invoke(p, new Object[]{});
            if (ObjectUtil.isEmpty(idObj)) {
                type = "添加";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result ? Result.ok(type + "成功！") : Result.fail(type + "失败！");
    }

    @Override
    public Result<P> getById(Long id) {
        return Result.ok(this.baseMapper.selectById(id));
    }

    @Override
    public Result<List<P>> getByIds(Collection<Long> ids) {
        return Result.ok(this.baseMapper.selectBatchIds(ids));
    }

    @Override
    public Result<Page<P>> pageByMap(Map<String, Object> map) {
        //1.封装分页数据
        Page<P> page = new Page<>();
        if (!ObjectUtil.isEmpty(map.get("current"))) {
            page.setCurrent(NumberUtil.parseLong(map.get("current").toString()));
        }
        if (!ObjectUtil.isEmpty(map.get("size"))) {
            page.setSize(NumberUtil.parseLong(map.get("size").toString()));
        }

        //2.封装请求参数
        QueryWrapper<P> wrapper = mapToEqWrapper(map);

        //3.查询分页数据
        return Result.ok(this.baseMapper.selectPage(page, wrapper));
    }

    @Override
    public Result<List<P>> list(D d) {
        //1.获取map参数
        Map<String, Object> map = toMap(d);

        //2.封装请求参数
        QueryWrapper<P> wrapper = mapToLikeWrapper(map);

        return Result.ok(this.baseMapper.selectList(wrapper));
    }

    @Override
    public Result<Page<P>> page(D d) {
        //分页数据
        long current = 0, size = 0;
        try {
            Method currentMethod = d.getClass().getSuperclass().getMethod("getCurrent", new Class[]{});
            Method sizeMethod = d.getClass().getSuperclass().getMethod("getSize", new Class[]{});
            Object currentObj = currentMethod.invoke(d, new Object[]{});
            Object sizeObj = sizeMethod.invoke(d, new Object[]{});
            current = NumberUtil.parseLong(currentObj.toString());
            size = NumberUtil.parseLong(sizeObj.toString());
        } catch (Exception e) {
            log.error("~~~~~~~~~~~~~~~~~page方法异常了~~~~~~~~~~~~~~~~,当前页:{},分页数量:{}", current, size);
            e.printStackTrace();
        }

        //1.获取map参数
        Map<String, Object> map = toMap(d);

        //2.封装分页数据
        Page<P> page = new Page<>(current, size);

        //3.封装请求参数（模糊模糊匹配）
        QueryWrapper<P> wrapper = mapToLikeWrapper(map);

        //4.查询分页数据
        return Result.ok(this.baseMapper.selectPage(page, wrapper));
    }

    @Override
    public Result<Long> count(D d) {
        //1.获取map参数
        Map<String, Object> map = toMap(d);

        //2.封装请求参数
        QueryWrapper<P> wrapper = mapToEqWrapper(map);

        //3.查询个数
        return Result.ok(this.count(wrapper));
    }

    @Override
    public Result<String> enable(Collection<Long> ids) {
        boolean result = this.update().set(StatusEnum.ENABLE.getColumn(), StatusEnum.ENABLE.getValue())
                .set("update_time", LocalDateTime.now()).in("id", ids).update();
        return result ? Result.ok("启用成功！") : Result.fail("启用失败！");
    }

    @Override
    public Result<String> unable(Collection<Long> ids) {
        boolean result = this.update().set(StatusEnum.UNABLE.getColumn(), StatusEnum.UNABLE.getValue())
                .set("update_time", LocalDateTime.now()).in("id", ids).update();
        return result ? Result.ok("停用成功！") : Result.fail("停用失败！");
    }

    private static <D> Map<String, Object> toMap(D d) {
        //查询参数
        Map<String, Object> param = new HashMap<>();

        //本类类属性
        Field[] fields = d.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String name = field.getName();

            if (!"serialVersionUID".equals(name)) {
                String firstLetter = name.substring(0, 1).toUpperCase();
                String getterMethod = "get" + firstLetter + name.substring(1);
                try {
                    Method method = d.getClass().getMethod(getterMethod, new Class[]{});
                    Object value = method.invoke(d, new Object[]{});
                    if (value != null && value.toString() != "") {
                        param.put(StrUtil.toUnderlineCase(name), value);
                    }
                } catch (Exception e) {
                    log.error("~~~~~~~~~~~~~~~~~toMap方法异常了~~~~~~~~~~~~~~~~,属性名:{}", name);
                    e.printStackTrace();
                }
            }
        }
        return param;
    }

    private static <P> QueryWrapper<P> mapToEqWrapper(Map<String, Object> map) {
        QueryWrapper<P> wrapper = new QueryWrapper<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            if (!"current".equals(key) && !"size".equals(key)) {
                wrapper.eq(key, entry.getValue());
            }
        }
        return wrapper;
    }

    private static <P> QueryWrapper<P> mapToLikeWrapper(Map<String, Object> map) {
        QueryWrapper<P> wrapper = new QueryWrapper<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            if (!"current".equals(key) && !"size".equals(key)) {
                if (SpringUtil.getBean(MybatisPlusConfigProperties.class).getSelectLikeColumn().contains(key)) {
                    wrapper.like(key, entry.getValue());
                } else {
                    wrapper.eq(key, entry.getValue());
                }
            }
        }
        return wrapper;
    }
}
